﻿using Shinva.LADModel.Models;
using Shinva.Variables.Interface;
using Shinva.Variables.Models;
using Shinva.Variables.Type.bit;
using Shinva.Variables.Type.combination;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Shinva.LADModel.Abstractions
{
    /// <summary>
    /// 元器件节点节点基类，包括指令节点常开常闭，自定义FB、FC节点
    /// </summary>
    public abstract class ElementNodeBase : IGraphNode
    {
       
        
        public virtual string Name { get; set; } = "ElementNode";
        public int  Id { get; set; }
        public NodeType NodeType { get; set; } = NodeType.ElementNode;

        /// <summary>
        /// 这是变量表接口,存储变量名和变量实例的地方
        /// </summary>
        public VariableTableInterface variableTableInterface { get; set; } = new VariableTableInterface();



        /// <summary>
        /// 保存所有数据指针地方，之后要做更新数据指针的操作
        /// </summary>
        public DataPointerAssociation dataPointerAssociation { get; set; } =new DataPointerAssociation();


        /// <summary>
        /// 使能输入与输出，这里是为了快速访问，需要在变量表接口中拿到实例
        /// </summary>
        protected PlcBool en { get; set; }
        protected PlcBool eno { get; set; }
        public abstract PlcBool ENO { get; set; }
        public abstract PlcBool EN { get; set; }

        //是能输出线，遍历遍历图元时使用
        public Connector<PlcBool> enoLine { get; set; } =   new Connector<PlcBool> ();
        
        //使能输入线，访问前一个逻辑输出状态使用
        public Connector<PlcBool> enLine { get; set; } =   new Connector<PlcBool> ();




        public ElementNodeBase()
        {
            //先注册两个能流用的接口
            variableTableInterface.AddVariable("en",StorageType.Input,new PlcBool());
            variableTableInterface.AddVariable("eno",StorageType.Input,new PlcBool());

            //从接口中获取变量实例
            en = variableTableInterface.GetVariableValue<PlcBool>("en");
            eno = variableTableInterface.GetVariableValue<PlcBool>("eno");

        }

        /// <summary>
        /// 这个链接的方法还是在具体的实例类中实现吧，因为不同的ElementNode里边定义的接口不一样
        /// </summary>
        /// <param name="node">这个是要连接的节点</param>
        /// <param name="INname">本节点连接的接口名</param>
        /// <param name="OutName">要连接的节点的那个接口名</param>
        public  void Connect(IGraphNode node, string FromName, string ToName)
        {
            //先把本节点的使能线连接上
            var enoLine = new Connector<PlcBool>()
            {
                FromNode = this,
                ToNode = node,

                From = (PlcBool)this.GetInterfaceVariableByName(FromName),
                To = (PlcBool)node.GetInterfaceVariableByName(ToName)
            };
            this.enoLine = enoLine;

            //反向的一个Connector，目的是为了调试的时候可以快速的获取到当前的图元的状态，并且无需遍历
            var enLine = new Connector<PlcBool>()
            {
                FromNode = node,
                ToNode = this,

                From = (PlcBool)node.GetInterfaceVariableByName(ToName),
                To = (PlcBool)this.GetInterfaceVariableByName(FromName),
            };
            //图元节点可虚拟节点有一点不同，这里需要处理一下
            if (node is ElementNodeBase element)
            {
                //将反向的连接器放置到要连接到的节点中，作为该节点的使能来源
                element.enLine = enLine;

            }
            else if(node is VirtualNode vn)
            {
                if (vn.enLineDict.ContainsKey(ToName))
                {//如果这根线存在就修改一下
                    vn.enLineDict[ToName] = enLine;
                }
                else
                {//不存在就新创建一根
                    vn.enLineDict.Add(ToName, enLine);
                }

            }
            else
            {
                throw new Exception("节点的类型出乎意料哦");
            }



            
        }


        public abstract IPlcMember GetInterfaceVariableByName(string name);



        public int GetHeight()
        {
            return 0;
        }


    }
}
